package com.luo.chengrui.module.sa.service.role;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import com.luo.chengrui.module.sa.dal.dataobject.auth.AuthorizeViewDO;
import com.luo.chengrui.module.sa.dal.dataobject.role.PermissionViewDO;
import com.luo.chengrui.module.sa.dal.redis.RedisKeyConstants;
import com.luo.chengrui.module.sa.service.auth.AuthorizeService;
import com.luo.chengrui.module.sa.service.person.PersonService;
import com.luo.chengrui.module.sa.service.role.PermissionService;
import com.luo.chengrui.module.sa.service.role.RoleService;
import cn.iocoder.yudao.module.system.enums.permission.RoleCodeEnum;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.util.*;
import java.util.stream.Collectors;

import com.luo.chengrui.module.sa.dal.dataobject.role.PermissionDO;

import com.luo.chengrui.module.sa.dal.mysql.role.PermissionMapper;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;

/**
 * 角色菜单权限 Service 实现类
 *
 * @author 诚睿
 */
@Service
@Validated
public class PermissionServiceImpl implements PermissionService {

    @Resource
    private PermissionMapper permissionMapper;
    @Resource
    private AuthorizeService authorizeService;
    @Resource
    private RoleService roleService;
    @Resource
    private PersonService personService;

    /**
     * 获得自身的代理对象，解决 AOP 生效问题
     *
     * @return 自己
     */
    private PermissionServiceImpl getSelf() {
        return SpringUtil.getBean(getClass());
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = RedisKeyConstants.SA_MENU_ROLE_ID_LIST, key = "#roleId")
    // allEntries 清空所有缓存，主要一次更新涉及到的 menuIds 较多，反倒批量会更快
    public void assignRoleMenu(String roleId, Set<Long> menuIds) {
        // 获得角色拥有菜单编号
        Set<Long> dbMenuIds = convertSet(permissionMapper.selectListByRoleId(roleId), PermissionDO::getMenuId);
        // 计算新增和删除的菜单编号
        Collection<Long> createMenuIds = CollUtil.subtract(menuIds, dbMenuIds);
        Collection<Long> deleteMenuIds = CollUtil.subtract(dbMenuIds, menuIds);
        // 执行新增和删除。对于已经授权的菜单，不用做任何处理
        if (CollUtil.isNotEmpty(createMenuIds)) {
            permissionMapper.insertBatch(CollectionUtils.convertList(createMenuIds, menuId -> {
                PermissionDO entity = new PermissionDO();
                entity.setVersion(System.currentTimeMillis());
                entity.setRoleId(roleId);
                entity.setMenuId(menuId);
                return entity;
            }));
        }
        if (CollUtil.isNotEmpty(deleteMenuIds)) {
            permissionMapper.deleteListByRoleIdAndMenuIds(roleId, deleteMenuIds);
            // 清除掉已经逻辑删除的数据，这个表里面没必要进行逻辑删除。
            permissionMapper.clearDeletedData(roleId);
        }
    }

    @Override
    public Set<Long> getRoleMenuListByRoleIds(Collection<String> roleIds) {
        if (CollUtil.isEmpty(roleIds)) {
            return Collections.emptySet();
        }
        return convertSet(getSelf().getRoleMenuListByRoleIds(roleIds.stream().collect(Collectors.toList())), PermissionDO::getMenuId);
    }

    @Override
    public List<PermissionViewDO> getRoleMenuListByRoleIds(List<String> roleIds) {
        List<PermissionViewDO> permissions = new ArrayList<>();
        for (String roleId : roleIds) {
            permissions.addAll(getSelf().getRoleMenuListByRoleIdFromCache(roleId));
        }
        List<PermissionViewDO> distinctPermissions = new ArrayList<>();
        Map<Long, PermissionViewDO> distinctPermissionMap = new HashMap<>();
        permissions.stream().forEach(item -> {
            if (!distinctPermissionMap.containsKey(item.getMenuId())) {
                distinctPermissionMap.put(item.getMenuId(), item);
            }
        });
        distinctPermissionMap.forEach((key, value) -> distinctPermissions.add(value));
        return distinctPermissions;
    }

    /**
     * 根据role查询菜单权限，从缓存获取
     *
     * @param roleId
     * @return
     */
    @Override
    @Cacheable(value = RedisKeyConstants.SA_MENU_ROLE_ID_LIST, key = "#roleId")
    public List<PermissionViewDO> getRoleMenuListByRoleIdFromCache(String roleId) {
        return permissionMapper.getMenuListByRoleIds(Collections.singletonList(roleId));
    }


    @Override
    public List<PermissionViewDO> getMenuListByOrgFullId(String orgFullId) {
        List<AuthorizeViewDO> result = authorizeService.selectListCustomizeByFullIdFromCache(orgFullId);
        if (result.size() == 0) {
            return new ArrayList<>();
        }

        // 过滤到已经排除的继承角色
        List<String> roleIds = result.stream().filter(
                item -> "0".equals(item.getParentExcluded()) && "0".equals(item.getMyselfExcluded())
        ).map(AuthorizeViewDO::getRoleId).collect(Collectors.toList());

        if (roleIds.size() == 0) {
            return new ArrayList<>();
        }

        return getSelf().getRoleMenuListByRoleIds(roleIds);
    }


    @Override
    @Cacheable(value = RedisKeyConstants.SA_PERSON_PERMISSIONS_CODES, key = "#systemUserId")
    public List<String> getPersonPermissionCodeListBySystemUserIdFromCache(Long systemUserId) {
        List<String> personFullIds = personService.getPersonFullIdsBySystemUserIdFromCache(systemUserId);
        List<String> roles = new ArrayList<>();
        for (String fullId : personFullIds) {
            // 获得当前登录的角色。如果为空，说明没有权限
            List<AuthorizeViewDO> result = authorizeService.selectListCustomizeByFullIdFromCache(fullId);
            if (result != null && result.size() > 0) {

                List<String> roleIds = result.stream().filter(
                        item -> "0".equals(item.getParentExcluded()) && "0".equals(item.getMyselfExcluded())
                ).map(AuthorizeViewDO::getRoleId).collect(Collectors.toList());
                roles.addAll(roleIds);
            }
        }
        if (roles.size() == 0) {
            return Collections.emptyList();
        }

        //角色存在，查询角色所拥有的权限
        List<PermissionViewDO> rolePermissions = permissionMapper.getMenuListByRoleIds(roles);
        if (rolePermissions == null || rolePermissions.size() == 0) {
            return Collections.emptyList();
        }
        List<String> permissions = rolePermissions.stream().map(PermissionViewDO::getPermission).collect(Collectors.toList());

        return permissions;

    }


    @Override
    public boolean hasAnyPermissions(Long systemUserId, String... permissions) {
        // 如果为空，说明已经有权限
        if (ArrayUtil.isEmpty(permissions)) {
            return true;
        }

        List<String> personFullIds = personService.getPersonFullIdsBySystemUserIdFromCache(systemUserId);

        List<String> roles = new ArrayList<>();
        for (String fullId : personFullIds) {
            // 获得当前登录的角色。如果为空，说明没有权限
            List<AuthorizeViewDO> result = authorizeService.selectListCustomizeByFullIdFromCache(fullId);
            if (result != null && result.size() > 0) {

                // 判断角色之中是否包含超管角色
                List<String> superManager = result.stream().filter(item -> RoleCodeEnum.isSuperAdmin(item.getCode())).map(AuthorizeViewDO::getCode).collect(Collectors.toList());
                if (superManager != null && superManager.size() > 0) {
                    return true;
                }
                List<String> roleIds = result.stream().filter(
                        item -> "0".equals(item.getParentExcluded()) && "0".equals(item.getMyselfExcluded())
                ).map(AuthorizeViewDO::getRoleId).collect(Collectors.toList());
                roles.addAll(roleIds);
            }
        }
        if (roles.size() == 0) {
            return false;
        }

        //角色存在，查询角色所拥有的权限
        List<PermissionViewDO> rolePermissions = getSelf().getRoleMenuListByRoleIds(roles);
        if (rolePermissions == null || rolePermissions.size() == 0) {
            return false;
        }
        List<PermissionViewDO> hasPermission = rolePermissions.stream().filter(item ->
                CollUtil.contains(Arrays.stream(permissions).collect(Collectors.toList()), item.getPermission())
        ).collect(Collectors.toList());

        // 情况一：遍历判断每个权限，如果有一满足，说明有权限
        if (hasPermission == null || hasPermission.size() == 0) {
            return false;
        }
        return true;
    }

}
